package lambdasinaction.chap7;

import java.util.Spliterator;
import java.util.function.Consumer;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;

/**
 * Created by ThinkPad on 2017/8/22.
 */
public class WordCount {
    public static final String SENTENCE =
            " Nel   mezzo del cammin di nostra vita " +
                    "mi ritrovai in una selva oscura" +
                    " che la dritta via sra smarrita ";

    public static void main(String... args) {
//        System.out.println("Found " + countWordsIteratively(SENTENCE) + " words");
        System.out.println("Found " + countWords(SENTENCE) + " words");
    }

    public static int countWordsIteratively(String s) {
        int counter = 0;
        boolean lastSpace = true;
        for (char c : s.toCharArray()) {
            if (Character.isWhitespace(c)) {
                lastSpace = true;
            } else {
                if (lastSpace) counter++;
                lastSpace = Character.isWhitespace(c);
            }
        }
        return counter;
    }

    public static int countWords(String s) {
        Spliterator<Character> spliterator = new WordCounterSpliterator(s);
        Stream<Character> stream = StreamSupport.stream(spliterator,true);
        return countWords(stream);
    }

    private static int countWords(Stream<Character> stream) {
        WordCounter wordCounter = stream.reduce(new WordCounter(0,true),
                WordCounter::accumulate,WordCounter::combine);
        return wordCounter.getCounter();
    }

    private static class WordCounter {
        private final int counter;
        private final boolean lastSpace;

        public WordCounter(int counter, boolean lastSpace) {
            this.counter = counter;
            this.lastSpace = lastSpace;
        }

        public WordCounter accumulate(Character c) {
            if (Character.isWhitespace(c)) {
                return lastSpace ? this : new WordCounter(counter,true);
            } else {
                return lastSpace ? new WordCounter(counter+1,false) : this;
            }
        }

        public WordCounter combine(WordCounter wordCounter) {
            return new WordCounter(counter + wordCounter.counter,wordCounter.lastSpace);
        }

        public int getCounter() {
            return counter;
        }
    }

    private static class WordCounterSpliterator implements Spliterator<Character> {

        private final String string;
        private int currentChar = 0;

        public WordCounterSpliterator(String string) {
            this.string = string;
        }

        /**
         * 把String中当前位置的Character传给了Consumer,并让位置加一
         * @param action Consumer(消费者)是一个java内部类
         * @return
         */
        @Override
        public boolean tryAdvance(Consumer<? super Character> action) {
            action.accept(string.charAt(currentChar++));
            return currentChar < string.length();//如果新的指针位置小于String的总长,且还有要遍历的Characteristics
//            则tryAdvance返回true.
        }

        @Override
        public Spliterator<Character> trySplit() {
            int currentSize = string.length() - currentChar;
            if (currentSize < 10) {
                return null;
            }
            for (int splitPos = currentSize / 2 + currentChar;splitPos < string.length();splitPos++) {
//                字符串拆分只能在单词首位的空格拆
                if (Character.isWhitespace(string.charAt(splitPos))) {
                    Spliterator<Character> spliterator = new WordCounterSpliterator(string.substring(currentChar,splitPos));
                    currentChar = splitPos;
                    return spliterator;
                }
            }
            return null;
        }

        /**
         * 还需要遍历的元素的estimateSize就是这个Spliterator解析的String的总长度和当前遍历的位置的差
         * @return
         */
        @Override
        public long estimateSize() {
            return string.length() - currentChar;
        }

        /**
         *
         * @return ORDERED(顺序就是String中各个Character的次序),SIZED(estimateSize方法
         * 的返回值是精确的),SUBSIZED(trySplit方法创建的其他Spliterator也有确切的大小),
         * NONNULL(String中不能有为null的Character)和IMMUTABLE(在解析String时不能再添加
         * Character,因为String本身是一个不可变类)
         */
        @Override
        public int characteristics() {
            return ORDERED + SIZED + SUBSIZED + NONNULL + IMMUTABLE;
        }
    }
}
